﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using netDxf;
using netDxf.Entities;

namespace WHDXF
{
    public class NetDxfExtend
    {
        /// <summary>
        /// 文件路径
        /// </summary>
        /// <param name="inPath"></param>
        /// <returns>裁切信息</returns>
        private static  List<LineExtend> GetOrderLine(string inPath)
        {
            List<LineExtend> rtnList = new List<LineExtend>();           //返回的
            if (!File.Exists(inPath))
            {
                return rtnList;
            }
            DxfDocument dxfDocument = DxfDocument.Load(inPath);
//var bl = dxfDocument.Blocks;
            var aaa = dxfDocument.Polylines[0].Vertexes[0].Location;
            foreach (Spline spline in dxfDocument.Splines)
            {
                
            }
            var xx = dxfDocument.Splines[0].ControlPoints;
            List<SplineVertex> splineLine = xx.ToList();
            //var aaa = bl[0].Entities;
            List<Line> srcLinelist = dxfDocument.Lines.ToList();
            //dxfDocument.Blocks[0].Entities[0]
            List<Point> srcPointlist = dxfDocument.Points.ToList();
            //var aaa = srcPointlist[0];
            //var bbb = aaa.Location;

            PointInfo srcPo = GetSrcPoint(srcLinelist, srcPointlist);     ///准备转换坐标原始坐标左上角  作为新坐标系的顶点坐标
            List<LineExtend> lineList = ConvertLine(srcLinelist, srcPo);   //转换过坐标后的线段
            LineExtend[] operArray = new LineExtend[lineList.Count];           //操作的List

            lineList.CopyTo(operArray);  //转换过坐标后的线段
            List<LineExtend> operList = operArray.ToList();

            PointInfo originPoint = new PointInfo(0, 0);

            while (operList.Any())
            {
                LineExtend neaeestLine = NearestLine(originPoint, operList);
                rtnList.Add(neaeestLine);
                originPoint = neaeestLine.EndPoint;
                operList.Remove(neaeestLine);
            }


            return rtnList;

        }
        private static List<LineExtend> GetOrderLine(byte[] inbyte)
        {
            List<LineExtend> rtnList = new List<LineExtend>();           //返回的
            if (inbyte.Count()==0)
            {
                return rtnList;
            }
            Stream stream = new MemoryStream(inbyte);
            DxfDocument dxfDocument = DxfDocument.Load(stream);
            List<Line> srcLinelist = dxfDocument.Lines.ToList();
            List<Point> srcPointlist = dxfDocument.Points.ToList();
            if (srcLinelist.Count==0)
            {
                return rtnList;
            }
            //var aaa = srcPointlist[0];
            //var bbb = aaa.Location;

            PointInfo srcPo = GetSrcPoint(srcLinelist, srcPointlist);     ///准备转换坐标原始坐标左上角  作为新坐标系的顶点坐标
            List<LineExtend> lineList = ConvertLine(srcLinelist, srcPo);   //转换过坐标后的线段
            LineExtend[] operArray = new LineExtend[lineList.Count];           //操作的List

            lineList.CopyTo(operArray);  //转换过坐标后的线段
            List<LineExtend> operList = operArray.ToList();

            PointInfo originPoint = new PointInfo(0, 0);

            while (operList.Any())
            {
                LineExtend neaeestLine = NearestLine(originPoint, operList);
                rtnList.Add(neaeestLine);
                originPoint = neaeestLine.EndPoint;
                operList.Remove(neaeestLine);
            }


            return rtnList;

        }
        private static string GetModelValue(string FieldName, object obj)
        {
            try
            {
                Type Ts = obj.GetType();
                object o = Ts.GetProperty(FieldName).GetValue(obj, null);
                string Value = Convert.ToString(o);
                if (string.IsNullOrEmpty(Value)) return null;
                return Value;
            }
            catch
            {
                return null;
            }
        }

        public static string GetCutInfo(string inPath)
        {
            List<LineExtend> list = GetOrderLine(inPath);
            StringBuilder ordrSbuBuilder = new StringBuilder();
            int iCount = 0;
            if (list.Count == 0)
            {
                return "";
            }
            else if (list.Count == 1)
            {
                ordrSbuBuilder.Append(list[0].StartPoint.X + "," + list[0].StartPoint.Y + ",0");
                return ordrSbuBuilder.ToString();
            }
            else
            {
                foreach (LineExtend extend in list)
                {
                    if (iCount == list.Count - 1)
                    {
                        ordrSbuBuilder.Append("(" + extend.StartPoint.X + "," + extend.StartPoint.Y + ",1" + ")");
                        ordrSbuBuilder.Append("(" + extend.EndPoint.X + "," + extend.EndPoint.Y + ",0");
                    }
                    else
                    {
                    
                        ordrSbuBuilder.Append("(" + extend.StartPoint.X + "," + extend.StartPoint.Y + ",1" + ")");
                        ordrSbuBuilder.Append("(" + extend.EndPoint.X + "," + extend.EndPoint.Y + "");
                        if (list[iCount + 1].isSeries)
                        {
                            ordrSbuBuilder.Append(",1)");
                        }
                        else
                        {
                            ordrSbuBuilder.Append(",0)");
                        }
                     
                    }
                    //}
                    iCount++;
                }
            }
            return ordrSbuBuilder.ToString();
        }
        public static string GetCutInfo(byte[] inPath)
        {
            List<LineExtend> list = GetOrderLine(inPath);
            StringBuilder ordrSbuBuilder = new StringBuilder();
            int iCount = 0;
            if (list.Count == 0)
            {
                return "";
            }
            else if (list.Count == 1)
            {
                ordrSbuBuilder.Append(list[0].StartPoint.X + "," + list[0].StartPoint.Y + ",0");
                return ordrSbuBuilder.ToString();
            }
            else
            {
                foreach (LineExtend extend in list)
                {
                    if (iCount == list.Count - 1)
                    {
                        ordrSbuBuilder.Append( + extend.StartPoint.X + "," + extend.StartPoint.Y + ",1" );
                        ordrSbuBuilder.Append( + extend.EndPoint.X + "," + extend.EndPoint.Y + ",0");
                    }
                    else
                    {

                        ordrSbuBuilder.Append(+ extend.StartPoint.X + "," + extend.StartPoint.Y + ",1" );
                        ordrSbuBuilder.Append( + extend.EndPoint.X + "," + extend.EndPoint.Y + "");
                        if (list[iCount + 1].isSeries)
                        {
                            ordrSbuBuilder.Append(",1");
                        }
                        else
                        {
                            ordrSbuBuilder.Append(",0");
                        }

                    }
                    //}
                    iCount++;
                }
            }
            return ordrSbuBuilder.ToString();
        }

        private static  LineExtend NearestLine(PointInfo fromPoint, List<LineExtend> inSrcExtends)
        {
            LineExtend nearestLine = new LineExtend();
            nearestLine = inSrcExtends.FirstOrDefault(p => p.StartPoint.X == fromPoint.X && p.StartPoint.Y == fromPoint.Y);
            if (nearestLine != null)
            {
                nearestLine.isSeries = true;

                return nearestLine;
            }
            nearestLine = inSrcExtends.FirstOrDefault(p => p.EndPoint.X == fromPoint.X && p.EndPoint.Y == fromPoint.Y);
            if (nearestLine != null)
            {
                PointInfo temInfo = new PointInfo();
                temInfo = nearestLine.StartPoint;
                nearestLine.StartPoint = nearestLine.EndPoint;
                nearestLine.EndPoint = temInfo;
                nearestLine.isSeries = true;
                return nearestLine;
            }

            LineExtend tempExtend = new LineExtend();
            double minDit = 10000000;
            foreach (LineExtend line in inSrcExtends)
            {

                double dirStMM =
                    Math.Sqrt(Math.Pow((line.StartPoint.X - fromPoint.X), 2) +
                              Math.Pow((line.StartPoint.Y - fromPoint.Y), 2));
                double dirEndMM =
              Math.Sqrt(Math.Pow((line.EndPoint.X - fromPoint.X), 2) +
                        Math.Pow((line.EndPoint.Y - fromPoint.Y), 2));
                if (dirStMM < dirEndMM)
                {
                    if (dirStMM < minDit)
                    {
                        minDit = dirStMM;
                        tempExtend = line;
                        tempExtend.isSeries = false;
                    }

                }
                else
                {
                    if (dirEndMM < minDit)
                    {
                        minDit = dirEndMM;
                        tempExtend = line;
                        PointInfo temInfo = new PointInfo();
                        temInfo = tempExtend.StartPoint;
                        tempExtend.StartPoint = tempExtend.EndPoint;
                        tempExtend.EndPoint = temInfo;
                        tempExtend.isSeries = false;
                    }
                }
            }
            nearestLine = tempExtend;
            return nearestLine;
        }

        private  static List<LineExtend> ConvertLine(List<Line> srcLinelist, PointInfo srcPo)
        {
            List<LineExtend> rtnList = new List<LineExtend>();
            foreach (Line srcLine in srcLinelist)
            {
                LineExtend lineExtend = new LineExtend();
                lineExtend.StartPoint = ConvetPoint(srcLine.StartPoint, srcPo);
                lineExtend.EndPoint = ConvetPoint(srcLine.EndPoint, srcPo);
                lineExtend.DXFLine = srcLine;
                rtnList.Add(lineExtend);
            }
            return rtnList;
        }


        private static  PointInfo ConvetPoint(Vector3 srcPoint, PointInfo originPoint)
        {
            PointInfo rtnInfo = new PointInfo();

            rtnInfo.X = srcPoint.X - originPoint.X;
            rtnInfo.Y = originPoint.Y - srcPoint.Y;
            return rtnInfo;
        }

        /// <summary>
        /// 计算最小X,Y
        /// </summary>
        /// <param name="srcLinelist"></param>
        /// <param name="srcPointlist"></param>
        /// <returns></returns>
        private  static PointInfo GetSrcPoint(List<Line> srcLinelist, List<Point> srcPointlist)
        {
            PointInfo point = new PointInfo();
            List<double> XList = new List<double>();
            List<double> YList = new List<double>();
            double lineStMinX = srcLinelist.Select(s => s.StartPoint).ToList().Select(s => s.X).Min();
            double lineStMaxY = srcLinelist.Select(s => s.StartPoint).ToList().Select(s => s.Y).Max();
            double lineEndMinX = srcLinelist.Select(s => s.EndPoint).ToList().Select(s => s.X).Min();
            double lineEndMaxY = srcLinelist.Select(s => s.EndPoint).ToList().Select(s => s.Y).Max();

            XList.Add(lineStMinX);
            XList.Add(lineEndMinX);
            YList.Add(lineStMaxY);
            YList.Add(lineEndMaxY);
            //     double lineStMAxX = srcLinelist.Select(s => s.StartPoint).ToList().Select(s => s.X).Max();
            //double lineStMAxY = srcLinelist.Select(s => s.StartPoint).ToList().Select(s => s.Y).Max(); 
            //   double lineEndMAxX = srcLinelist.Select(s => s.EndPoint).ToList().Select(s => s.X).Max();
            //double lineEndMAxY = srcLinelist.Select(s => s.EndPoint).ToList().Select(s => s.Y).Max(); 
            List<PointInfo> pointInfos = new List<PointInfo>();
            foreach (var point1 in srcPointlist)
            {
                // Vector3 v3 = point1.Location;

                string bbb = GetModelValue("Position", point1);
                PointInfo pi = new PointInfo(bbb);
                pointInfos.Add(pi);
            }

            double pointMinX = pointInfos.Select(s => s.X).Min();
            double pointminY = pointInfos.Select(s => s.Y).Max();
            XList.Add(pointMinX);
            YList.Add(pointminY);

            point = new PointInfo();
            point.X = XList.Min();
            point.Y = YList.Max();
            return point;
        }

    }
    /// <summary>
    /// 算法使用的点
    /// </summary>
    public class PointInfo
    {
        public PointInfo(double x, double y)
        {
            X = x;
            Y = y;
            UpDown = 0;
        }

        public PointInfo(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                X = 0;
                Y = 0;
                UpDown = 0;
            }
            else
            {
                var arrXYZ = str.Split(',');
                if (arrXYZ.Count() == 3)
                {
                    X = Convert.ToDouble(arrXYZ[0]);
                    Y = Convert.ToDouble(arrXYZ[1]);
                    UpDown = 0;
                }
                else
                {
                    X = 0;
                    Y = 0;
                    UpDown = 0;
                }
            }

        }

        public PointInfo()
        {
            UpDown = 0;
        }

        public double X { get; set; }
        public double Y { get; set; }
        public int UpDown { get; set; }//1dowm 0-up

    }
    /// <summary>
    /// 算法中使用的线
    /// </summary>
    public class LineExtend
    {
        public PointInfo StartPoint { get; set; }
        public PointInfo EndPoint { get; set; }
        public Line DXFLine { get; set; }
        public bool isSeries { get; set; }
    }

}
